
#include "demo.h"

// Include necessary headers
// #include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>

// #include "det/YOLO5.hpp"  // Uncomment for YOLOv5
// #include "det/YOLO7.hpp"  // Uncomment for YOLOv7
#include "det/YOLO8.hpp"  // Uncomment for YOLOv8
// #include "det/YOLO9.hpp"  // Uncomment for YOLOv9
// #include "det/YOLO10.hpp" // Uncomment for YOLOv10
// #include "det/YOLO11.hpp" // Uncomment for YOLOv11
// #include "det/YOLO12.hpp" // Uncomment for YOLOv12

#include "utils.h"

#define TMP_IMAGE_PATH "tmp.jpg"


bool check_file_exist(std::string path) {
    FILE *f = fopen(path.data(), "rb");
    if (f) { fclose(f); return true; }
    return false;
}

// block method
int process_image(std::string model_path, std::string label_path, std::string input_image, std::string output_image, bool useGpu) {
    LOGI("process '%{public}s' -> '%{public}s' use model '%{public}s' with label file '%{public}s' (gpu=%{public}d)",
        input_image.c_str(), output_image.c_str(), model_path.c_str(), label_path.c_str(), int(useGpu));
    
    if (!check_file_exist(model_path)) {
        LOGE("Error: Could not open model: '%{public}s'", model_path.c_str());
        return -1;
    }
    if (!check_file_exist(label_path)) {
        LOGE("Error: Could not open label file: '%{public}s'", label_path.c_str());
        return -1;
    }

    try {
    
    YOLO8Detector detector(model_path, label_path, useGpu);
    
    cv::Mat image = cv::imread(input_image);
    if (image.empty()) {
        LOGE("Error: Could not open or find the image!\n");
        return -2;
    }

    // Detect objects in the image and measure execution time
    auto start = std::chrono::high_resolution_clock::now();
    std::vector<Detection> results = detector.detect(image);
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
                        std::chrono::high_resolution_clock::now() - start);

    LOGI("Detection completed in %{public}lld ms", duration.count());

    // Draw bounding boxes on the image
    detector.drawBoundingBox(image, results); // simple bbox drawing
    // detector.drawBoundingBoxMask(image, results); // Uncomment for mask drawing

    // Save the image
    // cv::imshow("Detections", image);
    // cv::waitKey(0); // Wait for a key press to close the window
    cv::imwrite(output_image, image);
    } catch (std::exception &ex) {
        LOGE("Error: %{public}s", ex.what());
        return -2;
    }

    return 0;
}

int capture_and_process_image(int camera_idx, std::string model_path, std::string label_path, std::string output_image, bool useGpu) {
    cv::VideoCapture cap = cv::VideoCapture(camera_idx);
    if (!cap.isOpened()) {
        LOGE("Error: Could not access camera with index: %{public}d", camera_idx);
        return -2;
    }

    cv::Mat frame;
    bool succ = cap.read(frame);
    if (succ) {
        cv::imwrite(TMP_IMAGE_PATH, frame);
        LOGI("the intermediate image from camera saved as '%{public}s'", TMP_IMAGE_PATH);
    } else {
        LOGE("Error: failed to capture image from camera %{public}d", camera_idx);
        return -2;
    }
    cap.release();

    return process_image(model_path, label_path, TMP_IMAGE_PATH, output_image, useGpu);
}
